#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <cxxabi.h>
#include <string.h>
#include <strings.h>
#include <assert.h>
#include "back_trace.h"




#define STR_PATH_OUT "back_trace_cpp.xml"
#define XML_NODE_FRAME "sf"
#define XML_NODE_BACK_TRACE "bt"
#define XML_NODE_FRAME_INDEX "id"
#define STR_NAME "fun"
#define XML_NODE_LIB "lib"


inline static void  PRINT_STACK(size_t *size){
 	printf ("Obtained %zd stack frames.\n", (*size));
}

inline static void PRINT_STACK_FRAME(FILE* f,char* lib,char *demangled_symb,int *i){
        fprintf (f,"  <%s %s='%s' %s='%s' %s='%d'/>\n",\
                 XML_NODE_FRAME,STR_NAME,\
	         demangled_symb,XML_NODE_LIB,lib,XML_NODE_FRAME_INDEX,(int)(*i));
}

inline static void PRINT_STACK_OPEN_NODE(FILE *f){
	fprintf(f," <%s>\n","stack_trace");
}

inline static void PRINT_STACK_CLOSE_NODE(FILE* f){
   fprintf(f," </%s>\n","stack_trace");
}


/**
 *Initialise le fichier de trace de la pile des appels  
 */
void back_trace_init()
{
}

/**
 *Ferme le fichier contenant la pile  
 */
void back_trace_finalize()
{
}


/**
 *Demangle le symbole passé en argument
 */
static inline void demangle_and_print(char* lib,char * symbole,int * idx,FILE* f)
{
  int status = -1; 
  char *demangledName = abi::__cxa_demangle(symbole, NULL, NULL, &status ); 
  if ( status == 0 ) 
    { 
      //std::cout <<"demangled  name: "<<demangledName << std::endl; 
      PRINT_STACK_FRAME(f,lib,demangledName,idx);
    }
  else
    {
      if(symbole !=NULL)
	PRINT_STACK_FRAME(f,lib,symbole,idx);
    } 
  free( demangledName );
}


/**
 *Affiche l'etat de la pile des appels, seule méthode exposée.
 **/
void back_trace_print (FILE * f)
{
  assert(f!=NULL);
  /*Ici il faut fixer la profondeur de la back trace, par défaut 10*/
  void *array[20];
  stack_info_t stack;
  char *func=NULL;
  char *lib=NULL;
  
  int i;
  
  stack.size = backtrace (array, 20);
  stack.strings = backtrace_symbols (array, stack.size);
 
  PRINT_STACK_OPEN_NODE(f);
  for (i = 0; i < (int)stack.size; i++)
    {
      
      /*Ici extraire les symboles sous le format {lib,function,offset}*/
      
      lib = strtok (stack.strings[i],"(");
      
      /*pch va contenir le symbole de la fonction appelée*/
      func = strtok (NULL, "+");
      
      /*demangling de la fonction f*/
      demangle_and_print(lib,func,&i,f);   		
    }
  PRINT_STACK_CLOSE_NODE(f);
  
  free (stack.strings);
}
